
package org.yuanqiframework.yuanqi.boot.log.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.yuanqiframework.yuanqi.boot.sys.dto.LoginUserDTO;
import org.yuanqiframework.yuanqi.boot.sys.entity.SysLoginLog;
import org.yuanqiframework.yuanqi.boot.sys.service.SysLoginLogService;
import org.yuanqiframework.yuanqi.core.utils.AddressUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Date;

/**
 * 登录日志记录处理
 */
@Aspect
@Component
public class LoginLogAspect {
    private static final Logger log = LoggerFactory.getLogger(LoginLogAspect.class);

    @Resource
    private SysLoginLogService sysLoginLogService;

    /**
     * 设置登录切入点
     */
    @Pointcut("execution(* org.yuanqiframework.yuanqi.boot.sys.controller.UserController.login(..))")
    public void loginPointcut() {
    }

    /**
     * 处理完登录请求后执行
     *
     * @param joinPoint 切点
     */
    @AfterReturning(pointcut = "loginPointcut()", returning = "jsonResult")
    public void doAfterReturning(JoinPoint joinPoint, Object jsonResult) {
        handleLog(joinPoint, null, jsonResult);
    }

    /**
     * 拦截登录异常操作
     *
     * @param joinPoint 切点
     * @param e         异常
     */
    @AfterThrowing(value = "loginPointcut()", throwing = "e")
    public void doAfterThrowing(JoinPoint joinPoint, Exception e) {
        handleLog(joinPoint, e, null);
    }

    @Async
    protected void handleLog(final JoinPoint joinPoint, final Exception e, Object jsonResult) {
        try {
            // 获取请求信息
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            if (attributes == null) {
                return;
            }
            HttpServletRequest request = attributes.getRequest();

            // 获取登录参数
            LoginUserDTO loginUserDTO = getLoginUserDTO(joinPoint);

            // *========数据库日志=========*//
            SysLoginLog loginLog = new SysLoginLog();
            assert loginUserDTO != null;
            loginLog.setUsername(loginUserDTO.getUsername()); // 用户名
            loginLog.setIp(request.getRemoteAddr()); // 主机地址
            loginLog.setAddress(AddressUtils.getRealAddressByIP(request.getRemoteAddr())); // 登录地点

            // 解析浏览器和操作系统信息
            String userAgent = request.getHeader("User-Agent");
            if (userAgent != null) {
                loginLog.setBrowser(parseBrowser(userAgent)); // 浏览器
                loginLog.setOs(parseOS(userAgent)); // 操作系统
            }

            loginLog.setLoginTime(new Date()); // 登录时间

            if (e != null) {
                loginLog.setStatus("1"); // 状态（0成功 1失败）
                loginLog.setMsg(e.getMessage()); // 错误消息
            } else {
                loginLog.setStatus("0"); // 状态（0成功 1失败）
                loginLog.setMsg("登录成功"); // 操作信息
            }

            // 保存数据库
            sysLoginLogService.save(loginLog);
        } catch (Exception exp) {
            // 记录本地异常日志
            log.error("==登录日志记录异常==");
            log.error("异常信息:{}", exp.getMessage());
            exp.printStackTrace();
        }
    }

    /**
     * 获取登录参数
     *
     * @param joinPoint 切点
     * @return 登录参数
     */
    private LoginUserDTO getLoginUserDTO(JoinPoint joinPoint) {
        Object[] args = joinPoint.getArgs();
        for (Object arg : args) {
            if (arg instanceof LoginUserDTO) {
                return (LoginUserDTO) arg;
            }
        }
        return null;
    }

    /**
     * 解析浏览器类型
     *
     * @param userAgent userAgent
     * @return 浏览器类型
     */
    private String parseBrowser(String userAgent) {
        if (userAgent == null) {
            return "未知";
        }
        if (userAgent.contains("Edg")) {
            return "Edge";
        } else if (userAgent.contains("Chrome")) {
            return "Chrome";
        } else if (userAgent.contains("Firefox")) {
            return "Firefox";
        } else if (userAgent.contains("Safari")) {
            return "Safari";
        } else if (userAgent.contains("Opera") || userAgent.contains("OPR")) {
            return "Opera";
        } else if (userAgent.contains("MicroMessenger")) {
            return "微信";
        } else {
            return "未知";
        }
    }

    /**
     * 解析操作系统类型
     *
     * @param userAgent userAgent
     * @return 操作系统类型
     */
    private String parseOS(String userAgent) {
        if (userAgent == null) {
            return "未知";
        }
        if (userAgent.contains("Windows NT")) {
            return "Windows";
        } else if (userAgent.contains("Mac OS")) {
            return "Mac OS";
        } else if (userAgent.contains("Linux")) {
            return "Linux";
        } else if (userAgent.contains("Android")) {
            return "Android";
        } else if (userAgent.contains("iPhone") || userAgent.contains("iPad")) {
            return "iOS";
        } else {
            return "未知";
        }
    }
}